package cn.trigram.date;

import static java.time.temporal.ChronoUnit.DAYS;
import static java.time.temporal.ChronoUnit.HOURS;
import static java.time.temporal.ChronoUnit.MINUTES;
import static java.time.temporal.ChronoUnit.MONTHS;
import static java.time.temporal.ChronoUnit.NANOS;
import static java.time.temporal.ChronoUnit.SECONDS;
import static java.time.temporal.ChronoUnit.WEEKS;
import static java.time.temporal.ChronoUnit.YEARS;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.time.ZoneId;
import java.util.Date;
import java.util.Objects;

/**
 * 时间日期计算器
 *
 * @version 1.0.0
 * @date 2022/07/28 11:29:26
 * @since 1.0.0
 */
public class DateTimeCalculator {

    private final LocalDateTime ldt1;

    private final LocalDateTime ldt2;

    /**
     * @param lessDate   较小的日期
     * @param largerDate 较大的日期
     */
    public DateTimeCalculator(Date lessDate, Date largerDate) {

        Objects.requireNonNull(lessDate, "日期参数不能为空");
        Objects.requireNonNull(largerDate, "日期参数不能为空");
        this.ldt1 = LocalDateTime.ofInstant(lessDate.toInstant(), ZoneId.systemDefault());
        this.ldt2 = LocalDateTime.ofInstant(largerDate.toInstant(), ZoneId.systemDefault());
    }

    /**
     * @param lessDate   较小的日期
     * @param largerDate 较大的日期
     */
    public DateTimeCalculator(LocalDateTime lessDate, LocalDateTime largerDate) {

        Objects.requireNonNull(lessDate, "日期参数不能为空");
        Objects.requireNonNull(largerDate, "日期参数不能为空");
        this.ldt1 = lessDate;
        this.ldt2 = largerDate;
    }

    /**
     * @param lessDate   较小的日期
     * @param largerDate 较大的日期
     */
    public DateTimeCalculator(LocalDate lessDate, LocalDate largerDate) {

        Objects.requireNonNull(lessDate, "日期参数不能为空");
        Objects.requireNonNull(largerDate, "日期参数不能为空");
        this.ldt1 = lessDate.atStartOfDay();
        this.ldt2 = largerDate.atStartOfDay();
    }

    /**
     * @param lessDate   较小的日期
     * @param largerDate 较大的日期
     */
    public DateTimeCalculator(LocalTime lessDate, LocalTime largerDate) {

        Objects.requireNonNull(lessDate, "日期参数不能为空");
        Objects.requireNonNull(largerDate, "日期参数不能为空");
        this.ldt1 = lessDate.atDate(LocalDate.now());
        this.ldt2 = largerDate.atDate(LocalDate.now());
    }

    /**
     * 年份间隔
     *
     * @return long
     */
    public long yearOfInterval() {

        return YEARS.between(ldt1, ldt2);
    }

    /**
     * 月份间隔
     *
     * @return long
     */
    public long monthOfInterval() {

        return MONTHS.between(ldt1, ldt2);
    }

    /**
     * 周数间隔
     *
     * @return long
     */
    public long weekOfInterval() {

        return WEEKS.between(ldt1, ldt2);
    }

    /**
     * 天数间隔
     *
     * @return long
     */
    public long dayOfInterval() {

        return DAYS.between(ldt1, ldt2);
    }

    /**
     * 小时数间隔
     *
     * @return long
     */
    public long hourOfInterval() {

        return HOURS.between(ldt1, ldt2);
    }

    /**
     * 分钟数间隔
     *
     * @return long
     */
    public long minutesOfInterval() {

        return MINUTES.between(ldt1, ldt2);
    }

    /**
     * 秒数间隔
     *
     * @return long
     */
    public long secondOfInterval() {

        return SECONDS.between(ldt1, ldt2);
    }

    /**
     * 纳秒数间隔
     *
     * @return long
     */
    public long nanosOfInterval() {

        return NANOS.between(ldt1, ldt2);
    }

    /**
     * 计算周期，周期包括年、月、日三个时间单位
     *
     * @return {@link Period }
     */
    public Period toPeriod() {

        return Period.between(ldt1.toLocalDate(), ldt2.toLocalDate());
    }

    /**
     * 计算持续时间，包括时、分、秒、毫秒、纳秒五个时间单位
     *
     * @return {@link Duration }
     */
    public Duration toDuration() {

        return Duration.between(ldt1, ldt2);
    }

    /**
     * 简短的时间周期的文字描述
     * <br/>
     * 比如：1年1个月1天
     */
    public String briefPeriodDesc() {
        final Period period = this.toPeriod();
        final StringBuilder builder = new StringBuilder();
        int years = period.getYears();
        if (years != 0) {
            builder.append(years).append("年");
        }
        int months = period.getMonths();
        if (months != 0) {
            builder.append(months).append("个月");
        }
        int days = period.getDays();
        if (days != 0) {
            builder.append(days).append("天");
        }
        final LocalDateTime tempLdt1 = ldt1.plusYears(years).plusMonths(months).plusDays(days);
        final Duration duration = Duration.between(tempLdt1, ldt2);
        final LocalTime lt = LocalTime.ofNanoOfDay(duration.toNanos());
        int hours = lt.getHour();
        if (hours != 0) {
            builder.append(hours).append("小时");
        }
        int minutes = lt.getMinute();
        if (minutes != 0) {
            builder.append(minutes).append("分钟");
        }
        int seconds = lt.getSecond();
        if (seconds != 0) {
            builder.append(seconds).append("秒");
        }
        int nanos = lt.getNano();
        if (nanos != 0) {
            builder.append(nanos).append("纳秒");
        }
        return builder.toString();
    }

    /**
     * 比较运算：x!=y
     *
     * @return boolean
     */
    public boolean isNeq() {
        return !this.ldt1.isEqual(this.ldt2);
    }

    /**
     * 比较运算：x==y
     *
     * @return boolean
     */
    public boolean isEq() {
        return this.ldt1.isEqual(this.ldt2);
    }

    /**
     * 比较运算：x&lt;y
     *
     * @return boolean
     */
    public boolean isLt() {
        return this.ldt1.isBefore(this.ldt2);
    }

    /**
     * 比较运算：x<=y
     *
     * @return boolean
     */
    public boolean isLte() {
        return !this.ldt1.isAfter(this.ldt2);
    }

    /**
     * 比较运算：x>y
     *
     * @return boolean
     */
    public boolean isGt() {
        return this.ldt1.isAfter(this.ldt2);
    }

    /**
     * 比较运算：x>=y
     *
     * @return boolean
     */
    public boolean isGte() {
        return !this.ldt1.isBefore(this.ldt2);
    }
}
